package org.hbhk.hxl.gateway.redis;

import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hbhk.hxl.gateway.boot.ApplicationContextUtil;
import org.hbhk.hxl.gateway.route.JsonUtil;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * **************************************************
 * 
 * @description redis工具类，底层使用redisson
 * 
 */
public class RedisUtil {

	private static final Log log = LogFactory.getLog(RedisUtil.class);

	private static final String DISTRIBUTED_LOCK_FLAG = "lock_";

	private static volatile RedissonClient redissonManager;

	private static Boolean localCache = false;

	public static RedissonClient getRedissonManager() {
		if (redissonManager == null) {
			synchronized (DISTRIBUTED_LOCK_FLAG) {
				if (redissonManager == null) {
					try {
						redissonManager = ApplicationContextUtil.getApplicationContext().getBean(RedissonClient.class);
						if (redissonManager == null) {
							localCache = true;
						}

					} catch (Exception e) {
						localCache = true;
						log.error("本地缓存");
					}

				}
			}
		}
		return redissonManager;
	}

	public static RedissonClient setRedissonManager(RedissonClient redissonManager) {
		RedisUtil.redissonManager = redissonManager;
		return redissonManager;
	}

	public static void lock(String lockname, long leaseTime, TimeUnit unit) {
		String key = DISTRIBUTED_LOCK_FLAG + lockname;
		RLock lock = getRedissonManager().getLock(key);
		// lock提供带timeout参数，timeout结束强制解锁，防止死锁 ：1分钟
		lock.lock(leaseTime, unit);
	}

	public static void publish(String topic, String json) {
		RTopic rTopic = getRedissonManager().getTopic(topic);
		rTopic.publish(json);
	}

	public static void unlock(String lockname) {
		String key = DISTRIBUTED_LOCK_FLAG + lockname;
		RLock lock = getRedissonManager().getLock(key);
		lock.unlock();
	}

	public static void lock(String lockname) {
		String key = DISTRIBUTED_LOCK_FLAG + lockname;
		RLock lock = getRedissonManager().getLock(key);
		// lock提供带timeout参数，timeout结束强制解锁，防止死锁 ：1分钟
		lock.lock(1, TimeUnit.MINUTES);
	}

	/**
	 * 从Redis获取key为name的数据，并封装为指定class实例，可能发生运行时异常
	 *
	 * @param <T>   泛型支持
	 * @param clazz
	 * @param name
	 * @return
	 */
	public static <T> T get(Class<T> clazz, String name) {
		if (localCache) {
			return GuavaCacheManager.getInstance().get(name);
		}
		RBucket<byte[]> keyObject = getRedissonManager().getBucket(name);
		byte[] bytes = keyObject.get();
		if (bytes == null) {
			return null;
		}
		return JsonUtil.deserialize(keyObject.get(), clazz);
	}

	/**
	 * 根据name清除数据
	 *
	 * @param name
	 */
	public static void remove(String name) {
		if (localCache) {
			GuavaCacheManager.getInstance().remove(name);
			return;
		}
		getRedissonManager().getBucket(name).delete();
	}

	/**
	 * 缓存数据到Redis,无超时
	 *
	 * @param name
	 * @param value
	 */
	public static void put(String name, Object value) {
		if (localCache) {
			GuavaCacheManager.getInstance().put(name, value);
			return;
		}
		RBucket<byte[]> keyObject = getRedissonManager().getBucket(name);
		keyObject.set(JsonUtil.serialize(value));
	}

	/**
	 * 缓存数据到Redis
	 *
	 * @param name
	 * @param value
	 * @param timeToLive
	 * @param timeUnit
	 */
	public static void put(String name, Object value, long timeToLive, TimeUnit timeUnit) {
		if (localCache) {
			GuavaCacheManager.getInstance().put(name, value);
			return;
		}
		RBucket<byte[]> keyObject = getRedissonManager().getBucket(name);
		keyObject.set(JsonUtil.serialize(value), timeToLive, timeUnit);
	}

	/**
	 * 按分钟（计算超时）缓存数据
	 *
	 * @param name
	 * @param value
	 * @param timeToLive
	 */
	public static void putCacheWithMinutes(String name, Object value, long timeToLive) {
		if (localCache) {
			GuavaCacheManager.getInstance().put(name, value);
			return;
		}
		RBucket<byte[]> keyObject = getRedissonManager().getBucket(name);
		keyObject.set(JsonUtil.serialize(value), timeToLive, TimeUnit.MINUTES);
	}

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-redisson.xml");
		RedissonClient redisson = (RedissonClient) applicationContext.getBean("redissonManager");
		// 首先获取redis中的key-value对象，key不存在没关系
		// System.out.println(get(UserEntity.class, DISTRIBUTED_LOCK_FLAG));
		put("keyBytes", "keyBytes");
		System.out.println(get(String.class, "keyBytes"));
		// RBucket<String> keyObject = redisson.getBucket("key");
		// RBucket<byte[]> keyObject = redisson.getBucket("keyBytes");
		// System.out.println("ok:" + keyObject.get());
		// 如果key存在，就设置key的值为新值value
		// 如果key不存在，就设置key的值为value
		// keyObject.set("value".getBytes());
		redisson.shutdown();
	}

}
